forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1import * as v from 'valibot'
2import { PackageRouteParamsSchema } from '#shared/schemas/package'
3import { CACHE_MAX_AGE_ONE_HOUR } from '#shared/utils/constants'
4
5/**
6 * GET /api/registry/vulnerabilities/:name or /api/registry/vulnerabilities/:name/v/:version
7 *
8 * Analyze entire dependency tree for vulnerabilities and deprecated dependencies.
9 * I does not rename this endpoint for backward compatibility.
10 */
11export default defineCachedEventHandler(
12 async event => {
13 const pkgParamSegments = getRouterParam(event, 'pkg')?.split('/') ?? []
14 const { rawPackageName, rawVersion } = parsePackageParams(pkgParamSegments)
15
16 try {
17 const { packageName, version: requestedVersion } = v.parse(PackageRouteParamsSchema, {
18 packageName: decodeURIComponent(rawPackageName),
19 version: rawVersion,
20 })
21
22 // If no version specified, resolve to latest using fast-npm-meta (lightweight)
23 let version: string | undefined = requestedVersion
24 if (!version) {
25 const latestVersion = await fetchLatestVersionWithFallback(packageName)
26 if (!latestVersion) {
27 throw createError({
28 statusCode: 404,
29 message: 'No latest version found',
30 })
31 }
32 version = latestVersion
33 }
34
35 return await analyzeDependencyTree(packageName, version)
36 } catch (error: unknown) {
37 handleApiError(error, {
38 statusCode: 502,
39 message: 'Failed to analyze vulnerabilities',
40 })
41 }
42 },
43 {
44 maxAge: CACHE_MAX_AGE_ONE_HOUR,
45 swr: true,
46 getKey: event => {
47 const pkg = getRouterParam(event, 'pkg') ?? ''
48 return `vulnerabilities:v1:${pkg.replace(/\/+$/, '').trim()}`
49 },
50 },
51)